//@Author: cyl
//@File: basic.go
//@Time: 2023/06/10 22:27:24
package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

var wg sync.WaitGroup

func consumer(queue chan string, num int) {
	// 消费者
	for i := 0; i < num; i++ {
		wg.Add(1)
		go func(val int) {
			defer wg.Done()
			queue <- strconv.Itoa(val)
			time.Sleep(time.Second * 3)
		}(i)
	}
}

func main() {
	defer wg.Wait()

	// 生产者
	var msg = make(chan string, 10) // 创建一个有缓冲的通信通道
	consumer(msg, 20)

	/**
	1、如果直接使用同步代码进行循环读取通道的信息，代码如下:
		for msg := range c {
			fmt.Println(msg)
		}
	2、会报以下错误:
		panic: close of closed channel
	3、原因:
		我们提交这样一个错误：首先从接收端关闭了一个 channel
		接着我们再次发送并关闭已经被关闭的 channel，这就导致了 panic 的出现
	4、解决办法: 需要使用另一个 goroutine，代码如下:
		go func() {
		for m := range msg {
			fmt.Println("msg:", m)
		}()
	5、总结:
		好了，现在可以从很多个 goroutines 中接收数据了!
		在这个例子中，我们等待 for / Go 迭代的完成，接收者 goroutine 通过管道使得接收同步;
		当循环发送数据结束时，主进程也就跟着结束了
	*/
	go func() {
		fmt.Println("开始执行代码...")
		// 取值方式一
		for m := range msg {
			fmt.Println("开始读取值...")
			fmt.Println("msg:", m)
		}

		// 取值方式二
		// for {
		// 	m, ok := <-msg
		// 	if !ok {
		// 		fmt.Println("已经没有值了...")
		// 		break
		// 	}
		// 	fmt.Println("开始读取值...")
		// 	fmt.Println("msg:", m)
		// }
	}()
	fmt.Println("同步代码主线程之行结束...")

	/**
	  执行结果:
	  同步代码主线程之行结束...
	  开始执行代码...
	  开始读取值...
	  msg: 1
	  开始读取值...
	  msg: 4
	  开始读取值...
	  msg: 2
	  开始读取值...
	  msg: 0
	  开始读取值...
	  msg: 8
	  开始读取值...
	  msg: 3
	  开始读取值...
	  msg: 7
	  开始读取值...
	  msg: 9
	  开始读取值...
	  msg: 5
	  开始读取值...
	  msg: 6
	*/
}
